#include <iostream>
#include <sstream>
#include "debug.h"
#include "ThreadManager.h"

bool ThreadManager::m_quit = false;

MyThread::MyThread()
{
	this->IsUsed = false;
	this->Func = NULL;
	this->Datas = NULL;
	this->Cond = SDL_CreateCond();
	this->Thread = SDL_CreateThread(threadWaiting, (void*)this);
	this->Finished = false;
}

MyThread::~MyThread()
{
	//SDL_CondSignal(this->Cond);
	//SDL_WaitThread(this->Thread, NULL);
	SDL_DestroyCond(this->Cond);
}

ThreadManager::ThreadManager()
{
}

ThreadManager::~ThreadManager()
{
	ThreadManager::Quit();
	int i = 0;
	for (int i = 0; i < THREAD_NUMBER; i++)
	{
		SDL_CondSignal(m_threads[i].Cond);
#pragma region Affichage debugage
#ifdef _DEBUG
		std::ostringstream oss;
		oss << "Waiting for thread #"; oss << i; oss << " to finish action";
		COUT_ENDL(oss.str());
#endif
#pragma endregion
		SDL_CondSignal(m_threads[i].Cond);
		m_threads[i].Finished = true;
		SDL_WaitThread(m_threads[i].Thread, NULL);
		//std::cout << "Thread #" << i << " exited normally." << std::endl;
		m_threads[i].Func = NULL;
		m_threads[i].Datas = NULL;
		m_threads[i].IsUsed = false;
	}
}

bool ThreadManager::GetQuit()
{
	return (m_quit);
}

void ThreadManager::Quit()
{
	m_quit = true;
}

bool ThreadManager::useThread(int (*_func)(void*), void* _datas)
{
	for (int i = 0; i < THREAD_NUMBER; i++)
	{
		if (m_threads[i].IsUsed == false)
		{
			m_threads[i].Func = _func;
			m_threads[i].Datas = _datas;
			m_threads[i].IsUsed = true;
			SDL_CondSignal(m_threads[i].Cond);
			return (true);
		}
	}
	return (false);
}

void ThreadManager::reinitThreads()
{
	for (int i = 0; i < THREAD_NUMBER; i++)
	{
		if (m_threads[i].IsUsed == true)
		{
			m_threads[i].Func = NULL;
			m_threads[i].Datas = NULL;
			m_threads[i].IsUsed = false;
			SDL_CondSignal(m_threads[i].Cond);
#pragma region Affichage debugage
#ifdef _DEBUG
			{
				std::ostringstream oss;
				oss << "Waiting for thread #"; oss << i; oss << " to finish action";
				COUT_ENDL(oss.str());
			}
#endif
#pragma endregion
			if (SDL_CondWaitTimeout(m_threads[i].Cond, NULL, 5000) == SDL_MUTEX_TIMEDOUT)
			{
#pragma region Affichage debugage
#ifdef _DEBUG
				{
					std::ostringstream oss;
					oss << "Thread #"; oss << i; oss << " too long, killing it.";
					COUT_ENDL(oss.str());
				}
#endif
#pragma endregion
				SDL_KillThread(m_threads[i].Thread);
				m_threads[i].Thread = SDL_CreateThread(threadWaiting, (void*)&m_threads[i]);
			}
		}
	}
}

int threadWaiting(void* _thread)
{
	MyThread* t = (MyThread*)_thread;
	while (ThreadManager::GetQuit() == false)
	{
		if (SDL_CondWait(t->Cond, NULL) == 0)
		{
			if (t->Func != NULL)
			{
				t->Func(t->Datas);
				t->Datas = NULL;
				t->Func = NULL;
				t->IsUsed = false;
			}
		}
		SDL_CondSignal(t->Cond);
	}
	while (SDL_CondWaitTimeout(t->Cond, NULL, 500) == SDL_MUTEX_TIMEDOUT && !t->Finished)
		SDL_CondSignal(t->Cond);
	return (0);
}

